/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.core.commands;

import java.util.Iterator;

import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.gef.commands.Command;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Operation;

import com.cea.papyrus.core.editor.IPropertyValue;
import com.cea.papyrus.core.editpart.GraphEdgeEditPart;
import com.cea.papyrus.core.editpart.GraphNodeEditPart;
import com.cea.papyrus.core.editpart.IUMLElementEditPart;
import com.cea.papyrus.core.figures.connection.EdgeFigure;
import com.cea.papyrus.core.helper.GraphEdgeHelper;
import com.cea.papyrus.core.helper.ModelerHelper;
import com.cea.papyrus.core.helper.NodeHelper;
import com.cea.papyrus.diagraminterchange2.di2.Di2Factory;
import com.cea.papyrus.diagraminterchange2.di2.DiagramElement;
import com.cea.papyrus.diagraminterchange2.di2.GraphConnector;
import com.cea.papyrus.diagraminterchange2.di2.GraphEdge;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;
import com.cea.papyrus.diagraminterchange2.di2.PapyrusKeyEnumeration;
import com.cea.papyrus.diagraminterchange2.di2.Property;
import com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge;

/**
 * 
 */
public class StereotypePropertiesDisplayCreateCommand extends Command {
	
	/**
	 * 
	 */
	protected String name;
	//private BehavioralFeature parent;
	/**
	 * 
	 */
	protected DiagramElement semanticParent;
	
	/**
	 * 
	 */
	protected NodeHelper factory;
	
	/**
	 * 
	 */
	protected GraphNode propertiesGraphNode;
	
	/**
	 * 
	 */
	protected DiagramElement parent;
	private IUMLElementEditPart editpart;
	
	/**
	 * 
	 * 
	 * @param semanticparent 
	 * @param name 
	 * @param parent 
	 */
	public StereotypePropertiesDisplayCreateCommand(String name, DiagramElement semanticparent, DiagramElement parent) {
		factory = new NodeHelper();
		setLabel("Display stereotype properties"+name);
		this.name = name;
		this.semanticParent = semanticparent;
		this.parent = parent;
	}
	
	
	/**
	 * 
	 * 
	 * @param semanticparent 
	 * @param parent 
	 */
	public StereotypePropertiesDisplayCreateCommand(DiagramElement semanticparent, DiagramElement parent) {
		factory = new NodeHelper();
		//name = factory.getName(parent);
		setLabel("Display stereotype properties "+name);
		this.semanticParent = semanticparent;
		this.parent = parent;
	}
	
	/**
	 * 
	 * 
	 * @param semanticparent 
	 * @param parent 
	 */
	public StereotypePropertiesDisplayCreateCommand(IUMLElementEditPart editPart, DiagramElement semanticparent, DiagramElement parent) {
		factory = new NodeHelper();
		//name = factory.getName(parent);
		setLabel("Display stereotype properties "+name);
		this.semanticParent = semanticparent;
		this.editpart = editPart;
		this.parent = parent;
	}
	
	/* (non-Javadoc)
	 * @see 
	 * 
	 * org.eclipse.gef.commands.Command#execute()
	 */
	/**
	 * 
	 */
	@Override
	public void execute() {
		if(canExecute()){
			//propertiesGraphNode = factory.createGraphElement(null,null,null,null);
			propertiesGraphNode = createGraphNode();
			propertiesGraphNode.setSemanticParent(semanticParent);
			
			//createProperty value
			Property di2property=Di2Factory.eINSTANCE.createProperty();
			di2property.setKey(PapyrusKeyEnumeration.PAPYRUSEDITPART.getLiteral());
			di2property.setValue(IPropertyValue.STEREOTYPE_PROPERTY_DISPLAY);
			propertiesGraphNode.getProperty().add(di2property);
			
			
			// set the size of the note relatively
			propertiesGraphNode.setSize(new Dimension(100,70));
			
			Element element = ((Uml1SemanticModelBridge)((GraphElement)semanticParent).getSemanticModel()).getElement();
			// if the element is a property or an operation we have to display the stereotype property note in the grant parent
			if((element instanceof org.eclipse.uml2.uml.Property) || (element instanceof Operation)){
				//in class diagram
				if(((GraphNode)parent).getContainer().getContainer()!=null){
				propertiesGraphNode.setPosition(new Point(((GraphElement)semanticParent).getContainer().getContainer().getPosition().x-150, 
															((GraphElement)semanticParent).getContainer().getContainer().getPosition().y));
				
				((GraphNode)parent).getContainer().getContainer().getContained().add(propertiesGraphNode);}
				else{//in other diagram as composite
					propertiesGraphNode.setPosition(new Point(((GraphElement)semanticParent).getPosition().x-150, 
					((GraphElement)semanticParent).getPosition().y));
					((GraphNode)parent).getContained().add(propertiesGraphNode);}
			}
			else if(semanticParent instanceof GraphEdge){
				Point anchorSourcePoint = ((GraphConnector)((GraphEdge)semanticParent).getAnchor().get(0)).getPosition();
				Point anchorTargetPoint = ((GraphConnector)((GraphEdge)semanticParent).getAnchor().get(1)).getPosition();
				propertiesGraphNode.setPosition(new Point(anchorSourcePoint.x+100, anchorSourcePoint.y-100));
				((GraphNode)parent).getContained().add(propertiesGraphNode);
			}
			else {
				propertiesGraphNode.setPosition(new Point(((GraphElement)semanticParent).getPosition().x-100, 
												((GraphElement)semanticParent).getPosition().y-100));
				((GraphNode)parent).getContained().add(propertiesGraphNode);
			}
			
			GraphEdgeHelper ge= new GraphEdgeHelper();
			GraphEdge edge = (GraphEdge)ge.createGraphElement(null, (GraphElement)parent, null, null);
			//createPropertyValue
			di2property=Di2Factory.eINSTANCE.createProperty();
			di2property.setKey(PapyrusKeyEnumeration.PAPYRUSEDITPART.getLiteral());
			di2property.setValue(IPropertyValue.STEREOTYPE_PROPERTY_DISPLAY_EDGE);
			edge.getProperty().add(di2property);
			
			Point sourcePos = new Point(propertiesGraphNode.getPosition().x+propertiesGraphNode.getSize().width, 
					propertiesGraphNode.getPosition().y+propertiesGraphNode.getSize().height);
			Point targetPos;
			if(semanticParent instanceof GraphEdge){
//				Point anchorSourcePoint = ((GraphConnector)((GraphEdge)semanticParent).getAnchor().get(0)).getPosition();
//				Point anchorTargetPoint = ((GraphConnector)((GraphEdge)semanticParent).getAnchor().get(1)).getPosition();
//				targetPos = middlePoint(anchorSourcePoint, anchorTargetPoint); 
				targetPos = middlePoint(((EdgeFigure)((GraphEdgeEditPart)editpart).getFigure()).getStart(), ((EdgeFigure)((GraphEdgeEditPart)editpart).getFigure()).getEnd());
			}
			else if (editpart instanceof GraphNodeEditPart){
				targetPos = ((GraphNodeEditPart)editpart).getFigure().getBounds().getLeft();
//				targetPos = new Point(((GraphElement)semanticParent).getPosition().x+2, 
//						((GraphElement)semanticParent).getPosition().y);
			} else {
				targetPos = new Point(0, 0);
			}

			// create source anchor/connector
			GraphConnector srcConnector = Di2Factory.eINSTANCE.createGraphConnector();
			srcConnector.setPosition(targetPos);
			// create target connector
			GraphConnector targetConnector = Di2Factory.eINSTANCE.createGraphConnector();
			targetConnector.setPosition(sourcePos);
			// connect to graphEdge [0]=source  [1]=target
			edge.getAnchor().add(srcConnector);
			edge.getAnchor().add(targetConnector);
			
			getSourceAnchor(edge).setGraphElement((GraphElement)semanticParent);
			getTargetAnchor(edge).setGraphElement(propertiesGraphNode);
			edge.setContainer((GraphElement)parent);

			//GraphEdgeHelper ge= new GraphEdgeHelper();
			//GraphEdge edge = (GraphEdge)ge.createGraphElement(null, null, null, null);
			
			// add GraphEdge to parent
			//((GraphElement)parent).getContained().add(node);
		}
		
	}

	/**
	 * Creates a graphNode.
	 * 
	 * @return 
	 */
	protected GraphNode createGraphNode(){
		return factory.createGraphElement(null,null,null,null);
	}
	
	/**
	 * Computes the middle point between p1 and p2.
	 * 
	 * @param p1 
	 * @param p2 
	 * 
	 * @return 
	 */
	protected Point middlePoint(Point p1, Point p2){
		Dimension d = p2.getDifference(p1);
		return new Point(p1.x + d.width / 2, p1.y + d.height / 2);
	}

	/**
	 * 
	 * 
	 * @param edge 
	 * 
	 * @return The target anchor of the specified edge.
	 */
	protected GraphConnector getTargetAnchor(GraphEdge edge) {
		return ((GraphConnector)edge.getAnchor().get(1));
	}

	/**
	 * 
	 * 
	 * @param edge 
	 * 
	 * @return The source anchor of the specified edge.
	 */
	protected GraphConnector getSourceAnchor(GraphEdge edge) {
		return ((GraphConnector)edge.getAnchor().get(0));
	}

	
	/* (non-Javadoc)
	 * @see org.eclipse.gef.commands.Command#redo()
	 */
	/**
	 * 
	 */
	@Override
	public void redo() {
		execute();
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.gef.commands.Command#undo()
	 */
	/**
	 * 
	 */
	@Override
	public void undo() {
		
	}
	
	/**
	 * This method tests if the graphNode is allowed to be created.
	 * 
	 * @return 
	 */
	@Override
	public boolean canExecute() {
		
		Iterator<Property> iterator = semanticParent.getProperty().iterator();
		int count=0;
		while(iterator.hasNext()){
			Property currentProp = iterator.next();
			if(currentProp.getKey().equals(ModelerHelper.PROPERTY_STEREOTYPE_PROPERTY_VALUES_DISPLAY)) {
				count++;
			}
		}
		
		return count==1; 
	}

}